package cc.vv.party.logger

import cc.vv.party.beans.model.Log
import cc.vv.party.beans.vo.RoleVO
import cc.vv.party.common.constants.AdminInfo
import cc.vv.party.common.constants.SysConsts
import cc.vv.party.logger.annotation.OperateLog
import commonx.core.json.jsonPath
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.aspectj.lang.reflect.MethodSignature
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.web.context.request.ServletRequestAttributes
import javax.servlet.http.HttpServletRequest


/**
 * @version 1.0.0
 * @author: Gyb
 * @date 2018-10-16
 * @description
 **/
@Aspect
@Component
open class LoggerAspect {

    private val logger by lazy { LoggerFactory.getLogger(LoggerAspect::class.java) }

    @Autowired
    lateinit var asyncRecorder: AsyncRecorder

    @Pointcut("@annotation(cc.vv.party.logger.annotation.OperateLog)")
    fun recordLog() {
    }

    @Around("recordLog()")
    fun doAroundMethod(proceedingJoinPoint: ProceedingJoinPoint): Any {
        val result = proceedingJoinPoint.proceed()
        try {
            val operateLog =
                (proceedingJoinPoint.signature as MethodSignature).method.getAnnotation(OperateLog::class.java)
            val request = (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes).request
            val session = request.session
            val log = Log()
            log.remoteIp = getRemoteIPAddr(request)
            log.createUser = AdminInfo.admin!!.id
            log.operateContent = "${session.getAttribute(SysConsts.SESSION_KEY_DEVICE)}${operateLog.content}"
            val userSession = session.getAttribute(SysConsts.SESSION_KEY_USER_INFO) as? MutableMap<*, *>
            if (userSession != null) {
                val obj = userSession["userRole"]
                val role = obj as List<RoleVO>
                log.operateRole = role.map { it.name }.toList().joinToString()
                val userInfo = userSession["userInfo"]
                if (userInfo is AdminInfo.Admin) {
                    val admin = userSession["userInfo"] as AdminInfo.Admin
                    log.operateAccount = admin.name
                    log.operateName = admin.name
                    log.operateId = admin.id
                } else {
                    log.operateAccount = userSession.jsonPath("$.curPartyMember.phone")
                    log.operateName = userSession.jsonPath("$.curPartyMember.name")
                    log.operateId = userSession["userId"] as String
                }
            }
            asyncRecorder.writeLog(log)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return result
    }

    private fun getRemoteIPAddr(request: HttpServletRequest): String {
        var ip = request.getHeader("X-Forwarded-For") ?: ""
        if (logger.isInfoEnabled) {
            logger.info("getIpAddress(HttpServletRequest) - X-Forwarded-For - String ip=$ip")
        }

        if (ip.isEmpty() || "unknown".equals(ip, ignoreCase = true)) {
            if (ip.isEmpty() || "unknown".equals(ip, ignoreCase = true)) {
                ip = request.getHeader("Proxy-Client-IP") ?: ""
                if (logger.isInfoEnabled) {
                    logger.info("getIpAddress(HttpServletRequest) - Proxy-Client-IP - String ip=$ip")
                }
            }
            if (ip.isEmpty() || "unknown".equals(ip, ignoreCase = true)) {
                ip = request.getHeader("WL-Proxy-Client-IP") ?: ""
                if (logger.isInfoEnabled) {
                    logger.info("getIpAddress(HttpServletRequest) - WL-Proxy-Client-IP - String ip=$ip")
                }
            }
            if (ip.isEmpty() || "unknown".equals(ip, ignoreCase = true)) {
                ip = request.getHeader("HTTP_CLIENT_IP") ?: ""
                if (logger.isInfoEnabled) {
                    logger.info("getIpAddress(HttpServletRequest) - HTTP_CLIENT_IP - String ip=$ip")
                }
            }
            if (ip.isEmpty() || "unknown".equals(ip, ignoreCase = true)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR") ?: ""
                if (logger.isInfoEnabled) {
                    logger.info("getIpAddress(HttpServletRequest) - HTTP_X_FORWARDED_FOR - String ip=$ip")
                }
            }
            if (ip.isEmpty() || "unknown".equals(ip, ignoreCase = true)) {
                ip = request.remoteAddr
                if (logger.isInfoEnabled) {
                    logger.info("getIpAddress(HttpServletRequest) - getRemoteAddr - String ip=$ip")
                }
            }
        } else if (ip.length > 15) {
            val ips = ip.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
            for (index in ips.indices) {
                val strIp = ips[index]
                if (!"unknown".equals(strIp, ignoreCase = true)) {
                    ip = strIp
                    break
                }
            }
        }
        return ip
    }
}